/**
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
** \file Table.cpp
** \version $Id$
*/

#include "Table.h"

#include "Object.h"

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>

int 
sqliteCallback(void* _table, int numCols, char** results, char** colNames) {
  /* Remember which row number we are at */
  static unsigned int rowNumber = 0;

  /* Cast the table back */
  Table* table = static_cast<Table*>(_table);

  /* Create the object array of this row */
  Object** rowArray = new Object*[numCols];
  for (unsigned int i = 0; i < numCols; ++i) {
    /* Get the column name */
    /* Turn it into an Object* and add it to the array */
  }
  Row* newRow = new Row(rowArray, numCols);

  /* Insert the row into the Table */
  table->addRow(newRow, rowNumber);
}

int
sqliteCountCallback(void* _table, int numCols, char** result, char** colName) {
  unsigned int numRows = 0;

  /* Cast the table back */
  Table* table = static_cast<Table*>(_table);

  /* Retrieve the row value from result */
  std::stringstream istr;
  std::string tempStr(result[0]);
  istr << tempStr;
  istr >> numRows;
  if (istr.fail()) {
    std::cerr << "Error: Count badly formed" << std::endl;
    exit(1);
  }

  /* Allocate that many rows in the Table*/
  table->allocateRows(numRows);
}

Row::Row()
: _numColumns(0),
  _privateRowArray(0)
{
}

Row::Row(Object** rowArray, const unsigned int numCols)
: _numColumns(numCols),
  _privateRowArray(rowArray)
{
}

Row::Row(const Row& other)
{
}

Row::~Row()
{
  if (_privateRowArray)
    delete [] _privateRowArray;
}

Object* 
Row::operator[](const unsigned int index)
{
  return _privateRowArray[index];
}

Table::Table()
: _privateTableRows(0),
  _numRows(0)
{
}

Table::Table(sqlite3* database)
{
  int returnValue;
  char* errMsg = 0;

  /* Find out the number of columns */
  {
    const char* countStatement = "SELECT COUNT(*) FROM Data";
    /* This probably doesnt work */
    returnValue = sqlite3_exec(database, countStatement, 
			       sqliteCountCallback, this, &errMsg);

    if (returnValue) {
      std::cerr << "Error: SQL Error: " << errMsg << std::endl;
      exit(1);
    }
  }

  /* Populate the table */
  {
    char* errMsg = 0;
    const char* selectStatement = "SELECT * FROM Data";
    /* This probably doesn't work */
    returnValue = sqlite3_exec(database, selectStatement,
			       sqliteCallback, this, &errMsg);

    if (returnValue) {
      std::cerr << "Error: SQL Error: " << errMsg << std::endl;
      exit(1);
    }
  }
}

Table::Table(const Table& other)
{
}

Table::~Table()
{
  if (!_privateTableRows)
    return;

  for (unsigned int i = 0; i < _numRows; ++i) {
    if (_privateTableRows[i])
      delete _privateTableRows[i];
  }
  delete [] _privateTableRows;
}

Row& 
Table::operator[](const unsigned int index) const
{
  return (*_privateTableRows[index]);
}

void
Table::allocateRows(const unsigned int numRows)
{
  _privateTableRows = new Row*[numRows];
}

void
Table::addRow(Row* newRow, const unsigned int position)
{
  if (_privateTableRows)
    _privateTableRows[position] = newRow;
}
